package org.NooLab.itexx.app.controller.analyzer;

import java.util.ArrayList;

import org.NooLab.utilities.nums.NumUtils;

public class SeriesUtilities {

	
	ArrayList<ArrayList<?>> series = new ArrayList<ArrayList<?>>();
	
	SeriesDescriptions descriptions = new SeriesDescriptions();

	private int documentSize; 
	
	// ========================================================================
	public SeriesUtilities(){
		
	}
	// ========================================================================
	
	
	public void setSeries(ArrayList<Integer> vList) {
		
		series.clear();
		series.add( (ArrayList<?>) vList.clone() ) ;
	}
	
	public void addSeries(ArrayList<Integer> arrayList) {
		
	}

	/**
	 * this applies a uni-dimensional perspective = just for a single series
	 * @param index the index of the series
	 */
	public void describeDensity(int index) {
		//
		SeriesDescription description = new SeriesDescription();
		
		description.setIndex(index);
		
		description.iiDifferences = getInterItemDifferences(index) ;
		description.iiBasicDesc = describeBasics( description.iiDifferences ) ;
		
		descriptions.getItems().add(description);
	}
	
	
	private ArrayList<Double> getInterItemDifferences(int index) {
		// 
		
		ArrayList<Double> iiD = new ArrayList<Double>();
		
		
		double dv,v,v1,v2;
		int type;
		
		if (index>=series.size()){
			return iiD;
		}
		ArrayList<?> values = series.get(index) ;
		if (values.size()==0){
			return iiD;
		}
		
		type = getType( values.get(0) );
		v1 = getValueFromRaw( values.get(0), type);
		
		for (int i=1;i<values.size();i++){
			v2 = getValueFromRaw( values.get(i), type);
			dv = v2-v1;
			iiD.add( dv );
			v1=v2;
		} // i-> all values
		
		return iiD;
	}
	
	
	private BasicDescription describeBasics(ArrayList<?> values) {
		// 
		BasicDescription d = new BasicDescription();
		
		double v,sum=0 ,qsum=0;
		int type=-1,p,n,pmx ,pmi ;
		ArrayList<Double> nums = new ArrayList<Double>();
		// if there are groups, this describes the separating positions between them
		ArrayList<Integer> groupDiv = new ArrayList<Integer>();
		ArrayList<Integer> groupDivPos = new ArrayList<Integer>();

		
		if (values.size()==0){
			return d;
		}
		
		d.count = values.size()+1;
		
		type = getType( values.get(0) );
		
		for (int i=0;i<values.size();i++){
			
			v = getValueFromRaw( values.get(i), type);
			
			sum = sum + v;
			qsum = qsum + (v*v);
			nums.add(v);
			
			if (d.max<v){ d.max=v; pmx = i; };
			if (d.min>v){ d.min=v; pmi = i; };
			
		} // i-> all values
		
		n = values.size()-1;
		if (n>=8){
			sum =sum - d.max - d.min;
			qsum = qsum - d.max*d.max - d.min*d.min;
			n=n-2;
		}
		
		d.variance = NumUtils.lazyVariance(sum, qsum, n);
		d.mean = (double)sum/((double)n) ;
		
		double stddev = Math.sqrt( d.variance );
		double sepDistance = stddev * 3.5 ;
		
		// are there clusters/groups ?
		if (n>=5){
			double rs=0; int zn=0;
			for (int i=0;i<nums.size()-1;i++){
				if ( (nums.get(i+1) - nums.get(i))>sepDistance){
					p = (int)(rs+ ( ((double)(nums.get(i+1) + nums.get(i)))/((double)2.0) )); 
					groupDiv.add(p); 
					groupDivPos.add(i);  
					d.groupsizes.add(zn); zn=0;
				}
				rs = rs+nums.get(i); zn++;
			}// i-> nums
			
		}// n>5 ?
		
		
		/*
		int groupsize=0;
		*/
		int wbiggestGroup=-1, wbiggestGroupSize = -1;
		// for word count
		for (int i=0;i<groupDivPos.size();i++){
			p = groupDivPos.get(i);
		}
		
		int ibiggestGroup=-1, ibiggestGroupSize = -1;
		// for item count
		for (int i=0;i<d.groupsizes.size();i++){
			p = d.groupsizes.get(i);
			if (ibiggestGroupSize<p){
				ibiggestGroupSize = p;
				ibiggestGroup = i;
			}
		}
		
		/* and now we should calculate contrasts :
		 *   - length of text (as word count) inside/outside group
		 *   - largest groups vs smallest groups
		 */
		
		d.centerInfimCount = 0.0; // how many (fraction of all occ.) items are closer (=smaller differences) than stddev in largest group?
		
		for (int i=0;i<d.groupsizes.size();i++){
			// ibiggestGroup
		}
		
		d.coeffVar = (0.1+d.variance)/(0.1+d.mean);
		d.relFrequency = ((double)d.count)/((double)documentSize) ;
		
		if (groupDiv.size()>0){
			d.nGroups = groupDiv.size()+1;
			d.groupDiv = (ArrayList<Integer>) groupDiv.clone();
			d.withinGroupSaliencyByOE = 0.0;
			int gp=0,z=0;
			for (int i=0;i<d.nGroups;i++){
				if (i < d.getGroupsizes().size()) {
					int gz = d.getGroupsizes().get(i);
					if (gz >= 2) {
						v = (((double) gz) / (d.groupDiv.get(i) + 1)) / d.relFrequency;
						d.withinGroupSaliencyByOE = d.withinGroupSaliencyByOE + v;
						z++;
					}
				}
			}// i-> all groups
			d.withinGroupSaliencyByOE = d.withinGroupSaliencyByOE /((double)z) ;
		}
		return d;
	}
	private double getValueFromRaw(Object vo, int type) {
		// 
		double v = 0.0;
		
		if (type==1){ v = (double)1.0*(int)((Integer)vo); }
		if (type==2){ v = (double)1.0*(long)((Long)vo); }
		if (type==3){ v = (double)((Double)vo); }

		return v;
	}
	
	private int getType(Object vobj) {
		// 
		int type=3;
		Object obj = vobj;
		String cn = obj.getClass().getSimpleName().toLowerCase();
		if ((obj instanceof Integer) || (cn.startsWith("int"))){
			type = 1;
		}
		if ((obj instanceof Long) || (cn.startsWith("long"))){
			type = 2;
		}

		return type;
	}


	public void setDocumentSize( int nwords) {
		// 
		documentSize = nwords;
	}
	
	
	
}
